package aliyun

import (
	"bytes"
	"encoding/base64"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"golang.org/x/exp/rand"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"path"
	"strings"
	"time"
)

type OssService struct {
	IsPrivate bool //是否上传至私有空间
}

func (handle OssService) GetOssObject() (buckets *oss.Bucket) {

	// 创建OSSClient实例。
	// yourEndpoint填写Bucket对应的Endpoint，以华东1（杭州）为例，填写为https://oss-cn-hangzhou.aliyuncs.com。其它Region请按实际情况填写。
	// yourAccessKeyId和yourAccessKeySecret填写RAM用户的访问密钥（AccessKey ID和AccessKey Secret）。
	client, ossErr := oss.New("https://oss-cn-beijing.aliyuncs.com", "LTAI5t9K6hgZBdgfNjr19oiG", "VLKzeRtzIIo3N7zJKGo0WchwMXdjAe")
	if ossErr != nil {
		panic(ossErr)
	}
	if handle.IsPrivate {
		bucket, err := client.Bucket("mkl2024")
		if err != nil {
			return nil
		}
		return bucket
	} else {
		bucket, err := client.Bucket("all2024")
		if err != nil {
			return nil
		}
		return bucket
	}
}

func (handle OssService) UploadFile(file *multipart.FileHeader, ossPath string, resetFileName bool) (ossFileName string) {
	bucket := handle.GetOssObject()
	fileName := file.Filename
	if resetFileName {
		str := RandomString(10)
		fileName = str + path.Ext(file.Filename)
	}
	f, _ := file.Open()
	ossFileName = ossPath + fileName
	err := bucket.PutObject(ossFileName, f)
	if err != nil {
		// TODO 上传失败，将文件存到一个文件夹，然后生成系统错误
		panic(err)
	}
	return
}

func (handle OssService) UploadImageBase64(ossFileName, imgBase64 string) error {
	// 创建OSSClient实例。
	client, ossErr := oss.New("https://oss-cn-beijing.aliyuncs.com", "LTAI5t9K6hgZBdgfNjr19oiG", "VLKzeRtzIIo3N7zJKGo0WchwMXdjAe")
	if ossErr != nil {
		panic(ossErr)
	}

	bucket, err := client.Bucket("all2024")
	if err != nil {
		return nil
	}

	// 解码base64字符串。
	data, err := base64.StdEncoding.DecodeString(imgBase64)
	if err != nil {
		return err
	}

	// 上传图片。
	err = bucket.PutObject(ossFileName, bytes.NewReader(data))
	if err != nil {
		return err
	}

	return nil
}

func (handle OssService) UploadString(ossPath string, str string) {
	bucket := handle.GetOssObject()
	storageType := oss.ObjectStorageClass(oss.StorageIA)
	if err := bucket.PutObject(ossPath, strings.NewReader(str), storageType); err != nil {
		// TODO 上传失败，将文件存到一个文件夹，然后生成系统错误
		panic(err)
	}
	return
}

func (handle OssService) Download(ossFileName string) string {
	bucket := handle.GetOssObject()
	// 下载文件到流。
	body, err := bucket.GetObject(ossFileName)
	if err != nil {
		panic(err)
	}
	// 数据读取完成后，获取的流必须关闭，否则会造成连接泄漏，导致请求无连接可用，程序无法正常工作。
	defer body.Close()

	data, err := ioutil.ReadAll(body)
	if err != nil {
		panic(err)
	}
	return string(data)
}

func (handle OssService) UploadFileLocation(filePath string, ossPath string, resetFileName bool) (ossFileName string) {
	bucket := handle.GetOssObject()
	_, fileName := path.Split(filePath)
	if resetFileName {
		str := RandomString(10)
		fileName = str + path.Ext(filePath)
	}
	ossFileName = ossPath + fileName
	err := bucket.PutObjectFromFile(ossFileName, filePath)
	if err != nil {
		panic(err)
	}
	return
}

func (handle OssService) GetFileUrl(filePath string) string {
	bucket := handle.GetOssObject()

	expires := int64((5 * time.Minute).Seconds())

	signedUrl, err := bucket.SignURL(filePath, "GET", expires)
	if err != nil {
		panic(err)
	}
	return strings.Replace(signedUrl, "-internal", "", -1)
}

func (handle OssService) GetFileBase64(filePath string) (error, string) {
	bucket := handle.GetOssObject()
	expires := int64((5 * time.Minute).Seconds())
	signedUrl, err := bucket.SignURL(filePath, "GET", expires)
	if err != nil {
		return err, ""
	}
	res, err := http.Get(signedUrl)

	if err != nil {
		return err, ""
	}
	defer res.Body.Close()
	// 读取获取的[]byte数据
	data, _ := ioutil.ReadAll(res.Body)
	base64Data := base64.StdEncoding.EncodeToString(data)
	return nil, base64Data
}

func (handle OssService) UploadFileByReader(newFileName string, reader io.Reader) (string, error) {
	bucket := handle.GetOssObject()
	err := bucket.PutObject(newFileName, reader)
	if err != nil {
		return "", err
	}

	expire := int64((30 * 24 * time.Hour).Seconds())
	signedURL, err := bucket.SignURL(newFileName, "GET", expire)
	if err != nil {
		return "", err
	}

	productionURL := "https://simplifly-private.oss-cn-beijing-internal.aliyuncs.com"
	if strings.HasPrefix(signedURL, productionURL) {
		signedURL = strings.Replace(signedURL, productionURL, "https://simplifly-private.oss-cn-beijing.aliyuncs.com", 1)
	}
	testURL := "https://test-simplifly-private.oss-cn-beijing-internal.aliyuncs.com"
	if strings.HasPrefix(signedURL, testURL) {
		signedURL = strings.Replace(signedURL, testURL, "https://test-simplifly-private.oss-cn-beijing.aliyuncs.com", 1)
	}

	return signedURL, nil
}

func RandomString(n int) string {
	randStr := time.Now().UnixNano()
	var letters = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
	rand.Seed(uint64(randStr))
	str := make([]byte, n)
	for i := range str {
		str[i] = letters[rand.Intn(len(letters))]
	}
	return string(str)
}
